'''基于均值生成函数时间序列预测'''
import numpy as np

def mgf(data, step=0):
    n = len(data)
    m = int(n/2)
    f = np.zeros((m, n+step), dtype=np.float16)
    for l in range(1, m+1):
        nl = n // l
        for i in range(l):
            sum = 0
            for j in range(nl):
                sum = sum + data[i + j * l]

            f[l-1, i] = sum / nl
        quotients = (n+step)//l
        mod = (n+step)%l
        for k in range(1, quotients):
            f[l-1, l*k: l*(1+k)] = f[l-1, :l]
        if mod:
            f[l-1, -1*mod:] = f[l-1, :mod]
    f[0,:] = 1.
    return f.T

def predict(data, step=1, thre=0.995):
    mean = np.mean(data)
    std = np.std(np.array(data))
    data = (data - mean) / std
    fxt = mgf(data)
    fxt_step = mgf(data, step)
    I2 = np.cov(fxt.T)
    e, EV = np.linalg.eig(I2)
    e1 = np.argsort(e)  # 计算e从小到大大索引值
    e1 = e1[::-1]
    e = e[e1] / sum(e)

    Devotem = np.cumsum(e)
    m = np.where(Devotem >= thre)[0][1]
    V = fxt @ EV[:, e1[:m]]

    fai0 = np.linalg.inv(V.T @ V) @ V.T @ data

    q0 = np.mean(data - V@fai0)
    f2 = fxt_step[:, e1[:m]]

    pre = f2[-1*step:]  @ fai0 + q0
    prediction = std * pre + mean
    return np.around(prediction, 1)


if __name__ == '__main__':
    # data=[2,4,6,8,4,2,6,8, 6, 8, 7, 4,5, 3,9, 1, 3, 9, 2, 9]
    data = [27.6, 26.8, 27.7, 28.0, 28.0, 27.4,
            26.8, 26.9, 28.1, 28.0, 28.0, 27.8,
            27.9, 27.2, 27.7, 26.8, 28.0, 27.6,
            27.3, 26.9, 28.1, 27.5, 26.9, 27.5,
            27.7, 26.8, 27.3, 27.3, 27.9, 27.3,
            27.5, 27.7, 27.3, 27.6, 28.8]
    print(predict(data, 5))
